home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / uemlsrc / display.c < prev    next >
C/C++ Source or Header  |  1987-08-24  |  34KB  |  991 lines

  1. /*
  2.  * The functions in this file
  3.  * handle redisplay. There are two halves,
  4.  * the ones that update the virtual display
  5.  * screen, and the ones that make the physical
  6.  * display screen the same as the virtual
  7.  * display screen. These functions use hints
  8.  * that are left in the windows by the
  9.  * commands.
  10.  */
  11. #include        <stdio.h>
  12. #include        <osbind.h>
  13. #include        "ed.h"
  14.  
  15. #define WFDEBUG 0                       /* Window flag debug.           */
  16. #define BELL    0x07
  17.  
  18. typedef struct  VIDEO {
  19.         short   v_flag;                 /* Flags                        */
  20.         char    v_text[];               /* Screen data.                 */
  21. }       VIDEO;
  22.  
  23. #define VFCHG   0x0001                  /* Changed.                     */
  24. #define VFEXT   0x0002                  /* extended (beyond column 80)  */
  25. #define VFREV   0x0004                  /* reverse ?                    */
  26. #define VFREQ   0x0008
  27. int     sgarbf  = TRUE;                 /* TRUE if screen is garbage    */
  28. int     mpresf  = FALSE;                /* TRUE if message in last line */
  29. int     vtrow   = 0;                    /* Row location of SW cursor    */
  30. int     vtcol   = 0;                    /* Column location of SW cursor */
  31. int     ttrow   = HUGE;                 /* Row location of HW cursor    */
  32. int     ttcol   = HUGE;                 /* Column location of HW cursor */
  33. int     lbound  = 0;                    /* leftmost column of current ln*/
  34. char    mlbuf[256];                     /* modeline buffer              */
  35. VIDEO   **vscreen;                      /* Virtual screen.              */
  36. VIDEO   **pscreen;                      /* Physical screen.             */
  37.  
  38. /*
  39.  * Initialize the data structures used
  40.  * by the display code. The edge vectors used
  41.  * to access the screens are set up. The operating
  42.  * system's terminal I/O channel is set up. All the
  43.  * other things get initialized at compile time.
  44.  * The original window has "WFCHG" set, so that it
  45.  * will get completely redrawn on the first
  46.  * call to "update".
  47.  */
  48. vtinit()
  49. {
  50.         register int    i;
  51.         register VIDEO  *vp;
  52.  
  53. #if ST
  54.         /* save current colors for later */
  55.         savecolor();
  56. #endif
  57.         (*term.t_open)();
  58.         vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
  59.         if (vscreen == NULL)
  60.                 abort();
  61.         pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
  62.         if (pscreen == NULL)
  63.                 abort();
  64.         for (i=0; i<term.t_nrow; ++i) {
  65.                 vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
  66.                 if (vp == NULL)
  67.                         abort();
  68.                 vp->v_flag = 0;
  69.                 vscreen[i] = vp;
  70.                 vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
  71.                 if (vp == NULL)
  72.                         abort();
  73.                 vp->v_flag = 0;
  74.                 pscreen[i] = vp;
  75.         }
  76. }
  77.  
  78. /*
  79.  * Clean up the virtual terminal
  80.  * system, in anticipation for a return to the
  81.  * operating system. Move down to the last line and
  82.  * clear it out (the next system prompt will be
  83.  * written in the line). Shut down the channel
  84.  * to the terminal.
  85.  */
  86. vttidy()
  87. {
  88.         mlerase();
  89.         movecursor(term.t_nrow, 0);
  90.         (*term.t_eeol)();
  91.         (*term.t_close)();
  92. }
  93.  
  94. /*
  95.  * Set the virtual cursor to
  96.  * the specified row and column on the
  97.  * virtual screen. There is no checking for
  98.  * nonsense values; this might be a good
  99.  * idea during the early stages.
  100.  */
  101. vtmove(row, col)
  102. register int row, col;
  103. {
  104.         vtrow = row;
  105.         vtcol = col;
  106. }
  107.  
  108. /*
  109.  * Write a character to the
  110.  * virtual screen. The virtual row and
  111.  * column are updated. If the line is too
  112.  * long put a "$" in the last column.
  113.  * This routine only puts printing characters
  114.  * into the virtual terminal buffers.
  115.  * Only column overflow is checked.
  116.  */
  117. vtputc(c)
  118. register int    c;
  119. {
  120.         register VIDEO  *vp;
  121.  
  122.         vp = vscreen[vtrow];
  123.         if (vtcol >= term.t_ncol) {
  124.                 vtcol = (vtcol + 0x07) & ~0x07;
  125.                 vp->v_text[term.t_ncol-1] = '$';
  126.         }
  127.         else if (c == '\t') {
  128.                 do {
  129.                         vtputc(' ');
  130.                 } while ((vtcol&0x07) != 0);
  131.         } else if (c<0x20 || c==0x7F) {
  132.                 vtputc('^');
  133.                 vtputc(c ^ 0x40);
  134.         } else
  135.                 vp->v_text[vtcol++] = c;
  136. }
  137.  
  138. /*
  139.  * put a character to the virtual screen in an extended line. If we are
  140.  * not yet on left edge, don't print it yet. check for overflow on
  141.  * the right margin.
  142.  */
  143. vtpute(c)
  144. register int c;
  145. {
  146.         register VIDEO      *vp;
  147.  
  148.         vp = vscreen[vtrow];
  149.         if (vtcol >= term.t_ncol) {
  150.                 vtcol = (vtcol + 0x07) & ~0x07;
  151.                 vp->v_text[term.t_ncol - 1] = '$';
  152.         }
  153.         else if (c == '\t') {
  154.                 do {
  155.                         vtpute(' ');
  156.                 } while (((vtcol + lbound)&0x07) != 0);
  157.         }
  158.         else if (c < 0x20 || c == 0x7F) {
  159.                 vtpute('^');
  160.                 vtpute(c ^ 0x40);
  161.         }
  162.         else {
  163.                 if (vtcol >= 0)
  164.                         vp->v_text[vtcol] = c;
  165.                 ++vtcol;
  166.         }
  167. }
  168.  
  169. /*
  170.  * Erase from the end of the
  171.  * software cursor to the end of the
  172.  * line on which the software cursor is
  173.  * located.
  174.  */
  175. vteeol()
  176. {
  177.         register VIDEO  *vp;
  178.  
  179.         vp = vscreen[vtrow];
  180.         while (vtcol < term.t_ncol)
  181.                 vp->v_text[vtcol++] = ' ';
  182. }
  183.  
  184. /*
  185.  * Make sure that the display is
  186.  * right. This is a three part process. First,
  187.  * scan through all of the windows looking for dirty
  188.  * ones. Check the framing, and refresh the screen.
  189.  * Second, make sure that "currow" and "curcol" are
  190.  * correct for the current window. Third, make the
  191.  * virtual and physical screens the same.
  192.  */
  193. update()
  194. {
  195.         register LINE   *lp;
  196.         register WINDOW *wp;
  197.         register VIDEO  *vp1;
  198.         register VIDEO  *vp2;
  199.         register int    i;
  200.         register int    j;
  201.         register int    c;
  202.  
  203. #if     ST
  204.         Bconout(2,0x1b);        /* hide cursor */
  205.         Bconout(2,'f');
  206. #endif
  207.         for (i = 0; i < term.t_nrow; ++i)
  208.                 vscreen[i]->v_flag &= ~VFREQ;
  209. #if     ST
  210.         wp = wheadp;
  211.         while (wp != NULL) {
  212.                 vscreen[wp->w_toprow+wp->w_ntrows]->v_flag |= VFREQ;
  213.                 wp = wp->w_wndp;
  214.         }
  215. #endif
  216.         wp = wheadp;
  217.         while (wp != NULL) {
  218.                 /* Look at any window with update flags set on.         */
  219.                 if (wp->w_flag != 0) {
  220.                         /* If not force reframe, check the framing.     */
  221.                         if ((wp->w_flag&WFFORCE) == 0) {
  222.                                 lp = wp->w_linep;
  223.                                 for (i=0; i<wp->w_ntrows; ++i) {
  224.                                         if (lp == wp->w_dotp)
  225.                                                 goto out;
  226.                                         if (lp == wp->w_bufp->b_linep)
  227.                                                 break;
  228.                                         lp = lforw(lp);
  229.                                 }
  230.                         }
  231.                         /* Not acceptable, better compute a new value   */
  232.                         /* for the line at the top of the window. Then  */
  233.                         /* set the "WFHARD" flag to force full redraw.  */
  234.                         i = wp->w_force;
  235.                         if (i > 0) {
  236.                                 --i;
  237.                                 if (i >= wp->w_ntrows)
  238.                                         i = wp->w_ntrows-1;
  239.                         } else if (i < 0) {
  240.                                 i += wp->w_ntrows;
  241.                                 if (i < 0)
  242.                                         i = 0;
  243.                         } else
  244.                                 i = wp->w_ntrows/2;
  245.                         lp = wp->w_dotp;
  246.                         while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) {
  247.                                 --i;
  248.                                 lp = lback(lp);
  249.                         }
  250.                         wp->w_linep = lp;
  251.                         wp->w_flag |= WFHARD;   /* Force full.          */
  252.                 out:
  253.                         /* Try to use reduced update. Mode line update  */
  254.                         /* has its own special flag. The fast update is */
  255.                         /* used if the only thing to do is within the   */
  256.                         /* line editing.                                */
  257.                         lp = wp->w_linep;
  258.                         i  = wp->w_toprow;
  259.                         if ((wp->w_flag&~WFMODE) == WFEDIT) {
  260.                                 while (lp != wp->w_dotp) {
  261.                                         ++i;
  262.                                         lp = lforw(lp);
  263.                                 }
  264.                                 vscreen[i]->v_flag |= VFCHG;
  265.                                 vtmove(i, 0);
  266.                                 for (j=0; j<llength(lp); ++j)
  267.                                         vtputc(lgetc(lp, j));
  268.                                 vteeol();
  269.                         } else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) {
  270.                                 while (i < wp->w_toprow+wp->w_ntrows) {
  271.                                         vscreen[i]->v_flag |= VFCHG;
  272.                                         vtmove(i, 0);
  273.                                         if (lp != wp->w_bufp->b_linep) {
  274.                                                 for (j=0; j<llength(lp); ++j)
  275.                                                         vtputc(lgetc(lp, j));
  276.                                                 lp = lforw(lp);
  277.                                         }
  278.                                         vteeol();
  279.                                         ++i;
  280.                                 }
  281.                         }
  282.                         if ((wp->w_flag&WFMODE) != 0)
  283.                                 modeline(wp);
  284.                         wp->w_flag  = 0;
  285.                         wp->w_force = 0;
  286.                 }
  287. /*
  288. #if     WFDEBUG
  289.                 modeline(wp);
  290.                 wp->w_flag =  0;
  291.                 wp->w_force = 0;
  292. #endif
  293. */
  294.                 wp = wp->w_wndp;
  295.         }
  296.         /* Always recompute the row and column number of the hardware   */
  297.         /* cursor. This is the only update for simple moves.            */
  298.         lp = curwp->w_linep;
  299.         currow = curwp->w_toprow;
  300.         while (lp != curwp->w_dotp) {
  301.                 ++currow;
  302.                 lp = lforw(lp);
  303.         }
  304.         curcol = 0;
  305.         i = 0;
  306.         while (i < curwp->w_doto) {
  307.                 c = lgetc(lp, i++);
  308.                 if (c == '\t')
  309.                         curcol |= 0x07;
  310.                 else if (c<0x20 || c==0x7F)
  311.                         ++curcol;
  312.                 ++curcol;
  313.         }
  314.         if (curcol >= term.t_ncol-1) {          /* Extended line.       */
  315.                 /* flag we are extended and changed */
  316.                 vscreen[currow]->v_flag |= VFEXT | VFCHG;
  317.                 updext();                       /* and output extended line */
  318.         } else
  319.                 lbound = 0;                     /* not extended line */
  320.         /* make sure no lines need to be de-extended because the cursor is
  321.          * no longer on them
  322.          */
  323.         wp = wheadp;
  324.         while (wp != NULL) {
  325.                 lp = wp->w_linep;
  326.                 i = wp->w_toprow;
  327.                 while (i < wp->w_toprow + wp->w_ntrows) {
  328.                         if (vscreen[i]->v_flag & VFEXT) {
  329.                                 /* always flag extended lines as changed */
  330.                                 vscreen[i]->v_flag |= VFCHG;
  331.                                 if ((wp != curwp) || (lp != wp->w_dotp) ||
  332.                                 (curcol < term.t_ncol - 1)) {
  333.                                         vtmove(i, 0);
  334.                                         for (j = 0; j < llength(lp); ++j)
  335.                                                 vtputc(lgetc(lp, j));
  336.                                         vteeol();
  337.                                         /* this line no longer is extended */
  338.                                         vscreen[i]->v_flag &= ~VFEXT;
  339.                                 }
  340.                         }
  341.                 lp = lforw(lp);
  342.                 ++i;
  343.                 }
  344.         /* and onward to the next window */
  345.         wp = wp->w_wndp;
  346.         }
  347.         /* Special hacking if the screen is garbage. Clear the hardware */
  348.         /* screen, and update your copy to agree with it. Set all the   */
  349.         /* virtual screen change bits, to force a full update.          */
  350.         if (sgarbf != FALSE) {
  351.                 for (i=0; i<term.t_nrow; ++i) {
  352.                         vscreen[i]->v_flag |= VFCHG;
  353.                         vp1 = pscreen[i];
  354.                         for (j=0; j<term.t_ncol; ++j)
  355.                                 vp1->v_text[j] = ' ';
  356.                 }
  357.                 movecursor(0, 0);               /* Erase the screen.    */
  358.                 (*term.t_eeop)();
  359.                 sgarbf = FALSE;                 /* Erase-page clears    */
  360.                 mpresf = FALSE;                 /* the message area.    */
  361.         }
  362.         /* Make sure that the physical and virtual displays agree.      */
  363.         /* Unlike before, the "updateline" code is only called with a   */
  364.         /* line that has been updated for sure.                         */
  365.         for (i=0; i<term.t_nrow; ++i) {
  366.                 vp1 = vscreen[i];
  367.                 j = vp1->v_flag;
  368.                 if (((j & VFCHG) != 0) || (((j & VFREV) == 0) !=
  369.                         ((j & VFREQ) ==0)))
  370.                         {
  371.                         vp2 = pscreen[i];
  372.                         updateline(i, &vp1->v_text[0], &vp2->v_text[0],
  373.                         &vp1->v_flag);
  374.                 }
  375.         }
  376.         /* Finally, update the hardware cursor and flush out buffers.   */
  377.         movecursor(currow, curcol-lbound);
  378.         (*term.t_flush)();
  379. #if     ST
  380.         Bconout(2,0x1b);        /* enable cursor */
  381.         Bconout(2,'e');
  382. #endif
  383. }
  384.  
  385. /*
  386.  * updext: update the extended line which the cursor is currently
  387.  * on at a column greater than the terminal width. The line
  388.  * will be scrolled right or left to let the user see where
  389.  * the cursor is
  390.  */
  391. updext()
  392. {
  393.         register int rcursor;   /* real cursor location */
  394.         register LINE *lp;      /* pointer to current line */
  395.         register int j;  /* index into line */
  396.  
  397.         /* calculate what column the real cursor will end up in */
  398.         rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
  399.         lbound = curcol - rcursor + 1;
  400.         /* scan through the line outputing characters to the virtual screen */
  401.         /* once we reach the left edge    */
  402.         vtmove(currow, -lbound);        /* start scanning offscreen */
  403.         lp = curwp->w_dotp;          /* line to output */
  404.         for (j=0; j<llength(lp); ++j)   /* until the end-of-line */
  405.                 vtpute(lgetc(lp, j));
  406.         /* truncate the virtual line */
  407.         vteeol();
  408.         /* and put a '$' in column 1 */
  409.         vscreen[currow]->v_text[0] = '$';
  410. }
  411.  
  412. /*
  413.  * Update a single line. This
  414.  * does not know how to use insert
  415.  * or delete character sequences; we are
  416.  * using VT52 functionality. Update the physical
  417.  * row and column variables. It does try an
  418.  * exploit erase to end of line. The RAINBOW version
  419.  * of this routine uses fast video.
  420.  */
  421. updateline(row, vline, pline, flags)
  422. int row;
  423. char    vline[];
  424. char    pline[];
  425. short   *flags;
  426. {
  427. #if     RAINBOW
  428.         register char   *cp1;
  429.         register char   *cp2;
  430.         register int    nch;
  431.  
  432.         cp1 = &vline[0];                        /* Use fast video.      */
  433.         cp2 = &pline[0];
  434.         putline(row+1, 1, cp1);
  435.         nch = term.t_ncol;
  436.         do {
  437.                 *cp2 = *cp1;
  438.                 ++cp2;
  439.                 ++cp1;
  440.         } while (--nch);
  441. #else
  442.         register char   *cp1;
  443.         register char   *cp2;
  444.         register char   *cp3;
  445.         register char   *cp4;
  446.         register char   *cp5;
  447.         register int    nbflag;
  448.         int     rev;
  449.         int     req;
  450.  
  451.         cp1 = &vline[0];                        /* Compute left match.  */
  452.         cp2 = &pline[0];
  453. #if     ST
  454.         rev = *flags & VFREV;
  455.         req = *flags & VFREQ;
  456.         if (rev != req) {
  457.                 movecursor(row, 0);     /* Go to start of line. */
  458.                 if (req)
  459.                         {
  460.                         Crawio(0x1b);
  461.                         Crawio('p');
  462.                         }
  463.                 else
  464.                         {
  465.                         Crawio(0x1b);
  466.                         Crawio('q');
  467.                         }
  468. /*              (*term.t_rev)(req != FALSE);*/
  469.                 /* scan through the line and dump it to the screen and
  470.                  * the virtual screen array
  471.                  */
  472.                 cp3 = &vline[term.t_ncol];
  473.                 while (cp1 < cp3) {
  474.                         (*term.t_putchar)(*cp1);
  475.                         ++ttcol;
  476.                         *cp2++ = *cp1++;
  477.                 }
  478.                 Crawio(0x1b);
  479.                 Crawio('q');            /* turn on reverse video */
  480.                 /* update the needed flags */
  481.                 *flags &= ~VFCHG;
  482.                 if (req)
  483.                         *flags |= VFREV;
  484.                 else
  485.                         *flags &= ~VFREV;
  486.                 return(TRUE);
  487.         }
  488. #endif
  489.         while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0]) {
  490.                 ++cp1;
  491.                 ++cp2;
  492.         }
  493.         /* This can still happen, even though we only call this routine */
  494.         /* on changed lines. A hard update is always done when a line   */
  495.         /* splits, a massive change is done, or a buffer is displayed   */
  496.         /* twice. This optimizes out most of the excess updating. A lot */
  497.         /* of computes are used, but these tend to be hard operations   */
  498.         /* that do a lot of update, so I don't really care.             */
  499.         if (cp1 == &vline[term.t_ncol])         /* All equal.           */
  500.                 return;
  501.         nbflag = FALSE;
  502.         cp3 = &vline[term.t_ncol];              /* Compute right match. */
  503.         cp4 = &pline[term.t_ncol];
  504.         while (cp3[-1] == cp4[-1]) {
  505.                 --cp3;
  506.                 --cp4;
  507.                 if (cp3[0] != ' ')              /* Note if any nonblank */
  508.                         nbflag = TRUE;          /* in right match.      */
  509.         }
  510.         cp5 = cp3;
  511.         if (nbflag == FALSE) {                  /* Erase to EOL ?       */
  512.                 while (cp5!=cp1 && cp5[-1]==' ')
  513.                         --cp5;
  514.                 if ( ((int)cp3-(int)cp5) <= 3)  /* Use only if erase is */
  515.                         cp5 = cp3;              /* fewer characters.    */
  516.         }
  517.         movecursor(row, (int)cp1-(int)&vline[0]);/* Go to start of line.*/
  518.         while (cp1 != cp5) {                    /* Ordinary.            */
  519.                 (*term.t_putchar)(*cp1);
  520.                 ++ttcol;
  521.                 *cp2++ = *cp1++;
  522.         }
  523.         if (cp5 != cp3) {                       /* Erase.               */
  524.                 (*term.t_eeol)();
  525.                 while (cp1 != cp3)
  526.                         *cp2++ = *cp1++;
  527.         }
  528.         *flags &= ~VFCHG;
  529. #endif
  530. }
  531.  
  532. /*
  533.  * Redisplay the mode line for
  534.  * the window pointed to by the "wp".
  535.  * This is the only routine that has any idea
  536.  * of how the modeline is formatted. You can
  537.  * change the modeline format by hacking at
  538.  * this routine. Called by "update" any time
  539.  * there is a dirty window.
  540.  */
  541. modeline(wp)
  542. register WINDOW *wp;
  543. {
  544.         register char   *cp;
  545.         register int    c;
  546.         register int    i;
  547.         register int    n;
  548.         register BUFFER *bp;
  549.         register int    lchar;
  550.         char            tline[82];
  551.  
  552.         n = wp->w_toprow+wp->w_ntrows;          /* Location.            */
  553.         vscreen[n]->v_flag |= VFCHG;            /* Redraw next time.    */
  554.         vtmove(n,0);
  555.         if (wp == curwp)
  556.                 lchar = '=';
  557.         else
  558.                 lchar = '-';
  559.  
  560.         vtputc(lchar);
  561.         bp = wp->w_bufp;
  562.         if ((bp->b_flag&BFCHG) != 0)            /* "*" if changed.      */
  563.                 vtputc('*');
  564.         else
  565.                 vtputc(lchar);
  566.         n  = 2;
  567. #if     ST
  568.         strcpy(tline," Uemail ST 3.3 (");       /* Buffer name.         */
  569. #else
  570.         strcpy(tline, "Uemail 3.3 (");
  571. #endif
  572.         /* display the modes */
  573.         if (wp->w_bufp->b_bmode&BMCMODE)
  574.                 strcat(tline, "C");
  575.         else if (wp->w_bufp->b_bmode&BMWRAP)
  576.                 strcat(tline, "Wrap");
  577.         else
  578.                 strcat(tline, "Fundamental");
  579.         strcat(tline,") ");
  580.  
  581.         cp = &tline[0];
  582.         while ((c = *cp++) != 0) {
  583.                 vtputc(c);
  584.                 ++n;
  585.         }
  586.         vtputc(lchar);
  587.         vtputc(lchar);
  588.         vtputc(' ');
  589.         n += 3;
  590.         cp = &bp->b_bname[0];
  591.         while ((c = *cp++) != 0) {
  592.                 vtputc(c);
  593.                 ++n;
  594.         }
  595.         vtputc(' ');
  596.         vtputc(lchar);
  597.         vtputc(lchar);
  598.         n += 3;
  599.         if (bp->b_fname[0] != 0) {              /* File name.           */
  600.                 cp = " File: ";
  601.                 while ((c = *cp++) != 0) {
  602.                         vtputc(c);
  603.                         ++n;
  604.                 }
  605.                 cp = &bp->b_fname[0];
  606.                 while ((c = *cp++) != 0) {
  607.                         vtputc(c);
  608.                         ++n;
  609.                 }
  610.                 vtputc(' ');
  611.                 ++n;
  612.         }
  613. #if     WFDEBUG
  614.         vtputc(lchar);
  615.         vtputc((wp->w_flag&WFMODE)!=0  ? 'M' : '-');
  616.         vtputc((wp->w_flag&WFHARD)!=0  ? 'H' : '-');
  617.         vtputc((wp->w_flag&WFEDIT)!=0  ? 'E' : '-');
  618.         vtputc((wp->w_flag&WFMOVE)!=0  ? 'V' : '-');
  619.         vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : '-');
  620.         n += 6;
  621. #endif
  622.         while (n < term.t_ncol) {               /* Pad to full width.   */
  623.                 vtputc(lchar);
  624.                 ++n;
  625.         }
  626. }
  627.  
  628. upmode()        /* update all the mode lines */
  629. {
  630.         register WINDOW *wp;
  631.  
  632.         wp = wheadp;
  633.         while (wp != NULL) {
  634.                 wp->w_flag |= WFMODE;
  635.                 wp = wp->w_wndp;
  636.         }
  637. }
  638.  
  639. /*
  640.  * Send a command to the terminal
  641.  * to move the hardware cursor to row "row"
  642.  * and column "col". The row and column arguments
  643.  * are origin 0. Optimize out random calls.
  644.  * Update "ttrow" and "ttcol".
  645.  */
  646. movecursor(row, col)
  647. register int row, col;
  648. {
  649.         if (row!=ttrow || col!=ttcol) {
  650.                 ttrow = row;
  651.                 ttcol = col;
  652.                 (*term.t_move)(row, col);
  653.         }
  654. }
  655.  
  656. /*
  657.  * Erase the message line.
  658.  * This is a special routine because
  659.  * the message line is not considered to be
  660.  * part of the virtual screen. It always works
  661.  * immediately; the terminal buffer is flushed
  662.  * via a call to the flusher (not on ST).
  663.  */
  664. mlerase()
  665. {
  666.         movecursor(term.t_nrow, 0);
  667. #if     ST
  668.         Bconout(2,0x1b);        /* ST Kill entire line command */
  669.         Bconout(2,'l');
  670. #else
  671.         (*term.t_eeol)();
  672.         (*term.t_flush)();
  673. #endif
  674.         mpresf = FALSE;
  675. }
  676.  
  677. /*
  678.  * Ask a yes or no question in
  679.  * the message line. Return either TRUE,
  680.  * FALSE, or ABORT. The ABORT status is returned
  681.  * if the user bumps out of the question with
  682.  * a ^G. Used any time a confirmation is
  683.  * required.
  684.  */
  685. mlyesno(prompt)
  686. char    *prompt;
  687. {
  688.         register int    c;
  689.         char            buf[64];
  690.  
  691.         for (;;) {
  692.                 strcpy(buf, prompt);
  693.                 strcat(buf, " [y/n]? ");
  694.                 mlwrite(buf);
  695.                 /* get the response */
  696.                 c = (*term.t_getchar)();
  697.  
  698.                 if (c == BELL)    /* Bail out! */
  699.                         return(ABORT);
  700.  
  701.                 if (c=='y' || c=='Y')
  702.                         return(TRUE);
  703.  
  704.                 if (c=='n' || c=='N')
  705.                         return(FALSE);
  706.         }
  707. }
  708.  
  709. /*
  710.  * Write a prompt into the message
  711.  * line, then read back a response. Keep
  712.  * track of the physical position of the cursor.
  713.  * If we are in a keyboard macro throw the prompt
  714.  * away, and return the remembered response. This
  715.  * lets macros run at full speed. The reply is
  716.  * always terminated by a carriage return. Handle
  717.  * erase, kill, and abort keys.
  718.  */
  719. mlreply(prompt, buf, nbuf)
  720. char    *prompt;
  721. char    *buf;
  722. int nbuf;
  723. {
  724.         return(mlreplt(prompt,buf,nbuf,'\n'));
  725. }
  726.  
  727. /* A more generalized prompt/reply function allowing the caller
  728.  * to specify the proper terminator. If the terminator is not
  729.  * a return ('\n') it will echo as "<NL>"
  730.  */
  731. mlreplt(prompt, buf, nbuf, eolchar)
  732. char *prompt;
  733. char *buf;
  734. int nbuf;
  735. char eolchar;
  736. {
  737.         register int    cpos;
  738.         register int    i;
  739.         register int    c;
  740.  
  741.         cpos = 0;
  742.         if (kbdmop != NULL) {
  743.                 while ((c = *kbdmop++) != '\0')
  744.                         buf[cpos++] = c;
  745.                 buf[cpos] = 0;
  746.                 if (buf[0] == 0)
  747.                         return (FALSE);
  748.                 return (TRUE);
  749.         }
  750. #if     ST
  751.         (*term.t_move)(term.t_nrow, 0); /* in case we're in terminal mode */
  752. #endif
  753.         mlwrite(prompt);
  754.         for (;;) {
  755.         /* get a character from the user. if it is a <ret>, change it
  756.          * to a <NL>
  757.          */
  758.                 c = (*term.t_getchar)();
  759.                 if (c == 0x0d)
  760.                         c = '\n';
  761.                 if (c == eolchar) {
  762.                         buf[cpos++] = 0;
  763.                         if (kbdmip != NULL) {
  764.                                 if (kbdmip+cpos > &kbdm[NKBDM-3]) {
  765.                                         ctrlg(FALSE, 0);
  766.                                         (*term.t_flush)();
  767.                                         return(ABORT);
  768.                                 }
  769.                                 for (i=0; i<cpos; ++i)
  770.                                         *kbdmip++ = buf[i];
  771.                         }
  772.                         (*term.t_putchar)('\r');
  773.                         ttcol = 0;
  774.                         (*term.t_flush)();
  775.                         if (buf[0] == 0)
  776.                                 return(FALSE);
  777.                         return(TRUE);
  778.                 } else if (c == 0x07) { /* Bell, abort */
  779.                         (*term.t_putchar)('^');
  780.                         (*term.t_putchar)('G');
  781.                         ttcol += 2;
  782.                         ctrlg(FALSE, 0);
  783.                         (*term.t_flush)();
  784.                         return(ABORT);
  785.                 } else if (c == 0x7F || c == 0x08 || c == 0x02) {
  786.                         /* rubout/erase/cursor left */
  787.                         if (cpos != 0) {
  788.                                 (*term.t_putchar)('\b');
  789.                                 (*term.t_putchar)(' ');
  790.                                 (*term.t_putchar)('\b');
  791.                                 --ttcol;
  792.                                 if (buf[--cpos] < 0x20) {
  793.                                         (*term.t_putchar)('\b');
  794.                                         (*term.t_putchar)(' ');
  795.                                         (*term.t_putchar)('\b');
  796.                                         --ttcol;
  797.                                 }
  798.                                 if (buf[cpos] == '\n') {
  799.                                         (*term.t_putchar)('\b');
  800.                                         (*term.t_putchar)('\b');
  801.                                         (*term.t_putchar)(' ');
  802.                                         (*term.t_putchar)(' ');
  803.                                         (*term.t_putchar)('\b');
  804.                                         (*term.t_putchar)('\b');
  805.                                         --ttcol;
  806.                                         --ttcol;
  807.                                 }
  808.                                 (*term.t_flush)();
  809.                         }
  810.                 } else if (c == 0x15) { /* C-U, kill */
  811.                         while (cpos != 0) {
  812.                                 (*term.t_putchar)('\b');
  813.                                 (*term.t_putchar)(' ');
  814.                                 (*term.t_putchar)('\b');
  815.                                 --ttcol;
  816.                                 if (buf[--cpos] < 0x20) {
  817.                                         (*term.t_putchar)('\b');
  818.                                         (*term.t_putchar)(' ');
  819.                                         (*term.t_putchar)('\b');
  820.                                         --ttcol;
  821.                                 }
  822.                         }
  823.                         (*term.t_flush)();
  824.                 } else {
  825.                         if (cpos < nbuf-1) {
  826.                                 buf[cpos++] = c;
  827.                                 if ((c < ' ') && (c != '\n')) {
  828.                                         (*term.t_putchar)('^');
  829.                                         ++ttcol;
  830.                                         c ^= 0x40;
  831.                                 }
  832.                                 if (c != '\n')
  833.                                         (*term.t_putchar)(c);
  834.                                 else {  /* put out <NL> for <ret> */
  835.                                         (*term.t_putchar)('<');
  836.                                         (*term.t_putchar)('N');
  837.                                         (*term.t_putchar)('L');
  838.                                         (*term.t_putchar)('>');
  839.                                         ttcol += 3;
  840.                                 }
  841.                         ++ttcol;
  842.                         (*term.t_flush)();
  843.                         }
  844.                 }
  845.         }
  846. }
  847.  
  848. /*
  849.  * Write a message into the message
  850.  * line. Keep track of the physical cursor
  851.  * position. A small class of printf like format
  852.  * items is handled. Assumes the stack grows
  853.  * down; this assumption is made by the "++"
  854.  * in the argument scan loop. Set the "message
  855.  * line" flag TRUE.  For the ST this function
  856.  * uses sprintf() to get at ULONG and FLOAT
  857.  * arguments.  I couldn't get *VARARGS* to work
  858.  * so I kludged with the 10 long args.  Is this
  859.  * worth it?
  860.  */
  861. mlwrite(fmt, arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)
  862. char    *fmt;
  863. #if     ST
  864. long    arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10;
  865. {
  866.         /* Use the built-in functions on the ST.
  867.          * This lets us get to unsigned longs and floats
  868.          * but limits the number of arguments to 10.
  869.          */
  870.         mlerase();
  871.         mpresf = TRUE;
  872.         sprintf(mlbuf,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10);
  873.         ttputc(0x1b); ttputc('f');      /* hide cursor */
  874.         Cconws(mlbuf);
  875.         (*term.t_eeol)();
  876.         ttputc(0x1b); ttputc('e');      /* show cursor */
  877. }
  878. #else
  879. int arg;
  880. {
  881.         register int    c;
  882.         register char   *ap;
  883.  
  884.         movecursor(term.t_nrow, 0);
  885.         ap = (char *) &arg;
  886.         while ((c = *fmt++) != 0) {
  887.                 if (c != '%') {
  888.                         (*term.t_putchar)(c);
  889.                         ++ttcol;
  890.                 } else {
  891.                         c = *fmt++;
  892.                         switch (c) {
  893.                         case 'd':
  894.                                 mlputi(*(int *)ap, 10);
  895.                                 ap += sizeof(int);
  896.                                 break;
  897.  
  898.                         case 'o':
  899.                                 mlputi(*(int *)ap,  8);
  900.                                 ap += sizeof(int);
  901.                                 break;
  902.  
  903.                         case 'x':
  904.                                 mlputi(*(int *)ap, 16);
  905.                                 ap += sizeof(int);
  906.                                 break;
  907.  
  908.                         case 'D':
  909.                                 mlputli(*(long *)ap, 10);
  910.                                 ap += sizeof(long);
  911.                                 break;
  912.  
  913.                         case 's':
  914.                                 mlputs(*(char **)ap);
  915.                                 ap += sizeof(char *);
  916.                                 break;
  917.  
  918.                         default:
  919.                                 (*term.t_putchar)(c);
  920.                                 ++ttcol;
  921.                         }
  922.                 }
  923.         }
  924.         (*term.t_eeol)();
  925.         (*term.t_flush)();
  926.         mpresf = TRUE;
  927. }
  928.  
  929. /*
  930.  * Write out a string.
  931.  * Update the physical cursor position.
  932.  * This assumes that the characters in the
  933.  * string all have width "1"; if this is
  934.  * not the case things will get screwed up
  935.  * a little.
  936.  */
  937. mlputs(s)
  938. register char   *s;
  939. {
  940.         register int    c;
  941.  
  942.         while ((c = *s++) != 0) {
  943.                 (*term.t_putchar)(c);
  944.                 ++ttcol;
  945.         }
  946. }
  947.  
  948. /*
  949.  * Write out an integer, in
  950.  * the specified radix. Update the physical
  951.  * cursor position. This will not handle any
  952.  * negative numbers; maybe it should.
  953.  */
  954. mlputi(i, r)
  955. int i, r;
  956. {
  957.         register int    q;
  958.         static char hexdigits[] = "0123456789ABCDEF";
  959.  
  960.         if (i < 0) {
  961.                 i = -i;
  962.                 (*term.t_putchar)('-');
  963.         }
  964.         q = i/r;
  965.         if (q != 0)
  966.                 mlputi(q, r);
  967.         (*term.t_putchar)(hexdigits[i%r]);
  968.         ++ttcol;
  969. }
  970.  
  971. /*
  972.  * do the same except as a long integer.
  973.  */
  974. mlputli(l, r)
  975. long l;
  976. int r;
  977. {
  978.         register long q;
  979.  
  980.         if (l < 0) {
  981.                 l = -l;
  982.                 (*term.t_putchar)('-');
  983.         }
  984.         q = l/r;
  985.         if (q != 0)
  986.                 mlputli(q, r);
  987.         (*term.t_putchar)((int)(l%r)+'0');
  988.         ++ttcol;
  989. }
  990. #endif
  991.